#include "CrypUtil.h"
#include "depends/md5.h"
#include "depends/uz.h"
#include "depends/base64.h"

using namespace x2lib;

const char* CrypUtil::Md5(const uint8_t* pData, int nData, char buff[64])
{
	static char szMd5[64];

	char* pBuff = szMd5;
	if (buff) { pBuff = buff; }
	
	MD5_CTX mdContext;
	MD5Init(&mdContext);
	MD5Update(&mdContext, (unsigned char*)pData, nData);
	MD5Final(&mdContext);

	pBuff[0] = 0;
	for (int i = 0; i < sizeof(mdContext.digest); i++)
	{
		sprintf(pBuff, "%s%02x", pBuff, mdContext.digest[i]);
	}

	return pBuff;
}

const char* CrypUtil::Md5(const char* s, char buff[64])
{
	return Md5((const uint8_t*)s, strlen(s), buff);
}

void* CrypUtil::Base64(void* pData, int nData, void* pDataout, int* pnDataout, bool isEncrypt)
{
	if (isEncrypt) return (void*)base64_encode(pData, nData, (unsigned char*)pDataout, pnDataout);
	else return base64_decode((const char*)pData, pDataout, pnDataout);
}

void* CrypUtil::Encrypt(void* pIn, void* pOut, uint32_t nLen, uint8_t uKey)
{
	for (uint32_t i = 0; i < nLen; i++)
		((uint8_t*)pOut)[i] = ((uint8_t*)pIn)[i] ^ uKey;

	return pOut;
}

void* CrypUtil::Decrypt(void* pIn, void* pOut, uint32_t nLen, uint8_t uKey)
{
	return Encrypt(pIn, pOut, nLen, uKey);
}

void* CrypUtil::Encrypt1(void* pIn, void* pOut, uint32_t nLen, uint8_t uKey)
{
	memcpy(pOut, pIn, nLen);
	int i = nLen - 1;
	((char*)pOut)[i] ^= uKey;
	for (; i > 0; i--)
	{
		((char*)pOut)[i - 1] ^= ((char*)pOut)[i];
	}

	return pOut;
}

void* CrypUtil::Decrypt1(void* pIn, void* pOut, uint32_t nLen, uint8_t uKey)
{
	memcpy(pOut, pIn, nLen);
	for (uint32_t i = 0; i < nLen - 1; i++)
	{
		((char*)pOut)[i] ^= ((char*)pOut)[i + 1];
	}
	((char*)pOut)[nLen - 1] ^= uKey;

	return pOut;
}

void* CrypUtil::Encrypt2(void* pIn, void* pOut, uint32_t nLen, const char* szPwd)
{
	int nKey = strlen(szPwd);
	for (uint32_t i = 0; i < nLen; i++)
		*((uint8_t*)pOut + i) = *((uint8_t*)pIn + i) ^ szPwd[i % nKey];

	return pOut;
}

void* CrypUtil::Decrypt2(void* pIn, void* pOut, uint32_t nLen, const char* szPwd)
{
	return Encrypt2(pIn, pOut, nLen, szPwd);
}

uint32_t CrypUtil::CalcCrc32(void* pData, uint32_t nData)
{
	if (!pData || nData < 1) { return 0; }

    uint32_t crc = 0xFFFFFFFF;
    uint8_t* data = (uint8_t*)pData;

    for (uint32_t i = 0; i < nData; ++i)
    {
        crc ^= data[i];
        for (uint32_t j = 0; j < 8; ++j)
        {
            if (crc & 1) { crc = (crc >> 1) ^ 0xEDB88320; }
            else
            {
                crc = (crc >> 1);
            }
        }
    }

    return ~crc;
}
